package us.wili.dev.common.util.snowflake;

/**
 * Created by JasonY on 17/4/25.
 */

public class SnowflakeUtil {

    private final long workerId;
    private final static long twepoch = 1288834974657L; // unixtime起始时间，可设置为初始时间
    private long sequence = 0L;
    private final static long workerIdBits = 10L;
    private final static long maxWorkerId = -1L ^ (-1 << workerIdBits);
    private final static long sequenceBits = 12L;

    private final static long workerIdLeftShift = sequenceBits;
    private final static long timestampLeftShift = sequenceBits + workerIdBits;
    private final static long sequenceMax = -1 ^ (-1 << sequenceBits);

    private long lastTimestamp = -1L;

    public SnowflakeUtil(final String prefix, final long workerId) {
        if (workerId > this.maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(String.format("workerId cannot be greater than %d or less than 0", this.maxWorkerId));
        }

        this.workerId = workerId;
    }

    public SnowflakeUtil(final long workerId) {
        if (workerId > this.maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(String.format("workerId cannot be greater than %d or less than 0", this.maxWorkerId));
        }

        this.workerId = workerId;
    }

    public synchronized long nextId() {
        long timestamp = this.timeGen();

        if (this.lastTimestamp == timestamp) {
            this.sequence = (this.sequence + 1) & this.sequenceMax;

            if (this.sequence == 0) {
                timestamp = this.tilNextMills(this.lastTimestamp);
            }
        } else {
            this.sequence = 0;
        }

        if (timestamp < this.lastTimestamp) {
            throw new SnowflakeUtilException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", this.lastTimestamp - timestamp));
        }

        this.lastTimestamp = timestamp;
        return ((timestamp - twepoch << timestampLeftShift)) | (this.workerId << this.workerIdLeftShift) | (this.sequence);
    }

    private long tilNextMills(final long lastTimestamp) {
        long timestamp = timeGen();

        while (timestamp <= this.lastTimestamp) {
            timestamp = timeGen();
        }

        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }

    public static final void main(String[] args) {
        SnowflakeUtil snowflakeUtil = new SnowflakeUtil(2);
        try {
            System.out.println(snowflakeUtil.nextId());
        } catch (Exception e) {
            e.printStackTrace();
        }

        long current = System.currentTimeMillis();
        int num = 0;
        while (System.currentTimeMillis() - current < 1000) {
            try {
                snowflakeUtil.nextId();
            } catch (Exception e) {
                e.printStackTrace();
            }
            num ++;
        }

        System.out.print("1s内生成的ID数量为：" + num);
    }
}
